import 'package:dk_flutter_base/dk_core.dart';
import 'package:dk_flutter_base/dk_ui.dart';
import 'package:flutter/gestures.dart';

class DkText extends Text {
  DkText.simple(String data, double fontSize, Color fontColor,
      {Key key, FontWeight fontWeight, String fontFamily})
      : super(
          data ?? "",
          style: TextStyle(
            color: fontColor,
            fontSize: fontSize,
            fontWeight: fontWeight ?? FontWeight.w500,
          ),
          key: key,
        );

  DkText.withOption(TextOption option)
      : super(
          option.data,
          style: TextStyle(
            color: option.fontColor,
            fontSize: option.fontSize,
            fontStyle: option.fontStyle,
            fontWeight: option.fontWeight,
            letterSpacing: option.letterSpacing,
            wordSpacing: option.wordSpacing,
          ),
          overflow: option.overflow,
          maxLines: option.maxLines,
          textAlign: option.textAlign,
          key: option.key,
        );

  DkText.rich(DkTextSpan dkTextSpan, {TextOption option})
      : super.rich(
          dkTextSpan,
          style: TextStyle(
            color: option?.fontColor,
            fontSize: option?.fontSize,
            fontStyle: option?.fontStyle,
            fontWeight: option?.fontWeight,
            letterSpacing: option?.letterSpacing,
            wordSpacing: option?.wordSpacing,
          ),
          overflow: option?.overflow,
          maxLines: option?.maxLines,
          textAlign: option?.textAlign,
          key: option?.key,
        );
}

class TextOption {
  Key key;
  String data;
  double fontSize;
  Color fontColor;

  int maxLines;

  FontWeight fontWeight;
  FontStyle fontStyle;
  TextOverflow overflow;
  TextAlign textAlign;

  double letterSpacing;
  double wordSpacing;

  TextOption.simple(
    this.data,
    this.fontSize,
    this.fontColor, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    fontWeight ??= FontWeight.w500;
  }

  TextOption.lines(
    this.data,
    this.fontSize,
    this.fontColor,
    this.maxLines, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    fontWeight ??= FontWeight.w500;
  }

  TextOption.ellipsis(
    this.data,
    this.fontSize,
    this.fontColor, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    overflow = TextOverflow.ellipsis;
    fontWeight ??= FontWeight.w500;
  }

  TextOption.bold(this.data, this.fontSize, this.fontColor, {this.key}) {
    data ??= "";
    fontWeight = FontWeight.bold;
  }

  TextOption.italic(
    this.data,
    this.fontSize,
    this.fontColor, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    fontStyle ??= FontStyle.italic;
    fontWeight ??= FontWeight.w500;
  }

  TextOption.space(
    this.data,
    this.fontSize,
    this.fontColor,
    this.letterSpacing,
    this.wordSpacing, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    fontWeight ??= FontWeight.w500;
  }

  TextOption.align(
    this.data,
    this.fontSize,
    this.fontColor,
    this.textAlign, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    fontWeight ??= FontWeight.w500;
  }

  TextOption.fontWeight(
      this.data, this.fontSize, this.fontColor, this.fontWeight,
      {this.key}) {
    data ??= "";
  }

  TextOption.overflow(
    this.data,
    this.fontSize,
    this.fontColor,
    this.overflow, {
    this.key,
    this.fontWeight,
  }) {
    data ??= "";
    overflow ??= TextOverflow.ellipsis;
    fontWeight ??= FontWeight.w500;
  }

  TextOption(this.data,
      {this.fontSize,
      this.fontColor,
      this.maxLines,
      this.overflow,
      this.fontStyle,
      this.fontWeight,
      this.letterSpacing,
      this.wordSpacing,
      this.textAlign,
      this.key}) {
    data ??= "";
  }
}

class DkTextSpan extends TextSpan {
  DkTextSpan(
    String text,
    TextStyle style,
    GestureRecognizer recognizer,
    String semanticsLabel,
    List<TextSpan> children,
  ) : super(
          text: text,
          style: style,
          recognizer: recognizer,
          semanticsLabel: semanticsLabel,
          children: children,
        );

  DkTextSpan.single(
    String data,
    double fontSize,
    Color fontColor, {
    FontStyle fontStyle,
    FontWeight fontWeight,
    double letterSpacing,
    double wordSpacing,
    GestureRecognizer recognizer,
    String semanticsLabel,
  }) : super(
          text: data,
          style: TextStyle(
            fontSize: fontSize,
            color: fontColor,
            fontStyle: fontStyle,
            fontWeight: fontWeight,
            letterSpacing: letterSpacing,
            wordSpacing: wordSpacing,
          ),
          recognizer: recognizer,
          semanticsLabel: semanticsLabel,
        );

  DkTextSpan.singleWithTextOption(
    TextOption option, {
    GestureRecognizer recognizer,
    String semanticsLabel,
  }) : super(
          text: option.data,
          style: TextStyle(
            color: option.fontColor,
            fontSize: option.fontSize,
            fontStyle: option.fontStyle,
            fontWeight: option.fontWeight,
            letterSpacing: option.letterSpacing,
            wordSpacing: option.wordSpacing,
          ),
          recognizer: recognizer,
          semanticsLabel: semanticsLabel,
        );

  DkTextSpan.list(
    List<DkTextSpan> children,
  ) : super(children: children);

  DkTextSpan.withOption(TextSpanOption textSpanOption)
      : super(
          text: textSpanOption?.textOption?.data,
          style: TextStyle(
            fontSize: textSpanOption?.textOption?.fontSize,
            color: textSpanOption?.textOption?.fontColor,
            fontStyle: textSpanOption?.textOption?.fontStyle,
            fontWeight: textSpanOption?.textOption?.fontWeight,
            letterSpacing: textSpanOption?.textOption?.letterSpacing,
            wordSpacing: textSpanOption?.textOption?.wordSpacing,
          ),
          children: textSpanOption.children,
          recognizer: textSpanOption.recognizer,
          semanticsLabel: textSpanOption.semanticsLabel,
        );
}

class TextSpanOption {
  TextOption textOption;
  List<DkTextSpan> children;
  GestureRecognizer recognizer;
  String semanticsLabel;

  TextSpanOption({
    this.textOption,
    this.children,
    this.recognizer,
    this.semanticsLabel,
  }) {
    if (objEmpty(textOption)) {
      if (listEmpty(children)) {
        textOption = TextOption("");
      }
    } else if (objEmpty(textOption.data) && listEmpty(children)) {
      textOption.data = "";
    }
  }

  TextSpanOption.single(this.textOption) {
    if (objEmpty(textOption)) {
      textOption = TextOption("");
    } else if (objEmpty(textOption.data)) {
      textOption.data = "";
    }
  }

  TextSpanOption.list(this.children) {
    if (listEmpty(children)) {
      textOption = TextOption("");
    }
  }
}

class DkScaleText extends Container {
  final ScaleTextOption scaleTextOption;

  DkScaleText(this.scaleTextOption)
      : super(
          width: scaleTextOption.width,
          height: scaleTextOption.height,
          alignment: scaleTextOption.alignment,
          padding: EdgeInsets.only(
            top: scaleTextOption.paddingTop,
            left: scaleTextOption.paddingLeft,
          ),
          child: CustomPaint(painter: DkScaleTextPainter(scaleTextOption)),
        );
}

class ScaleTextOption {
  TextOption textOption;
  double width;
  double height;
  double scaleX;
  double scaleY;
  Alignment alignment;
  bool isVertical;
  double paddingTop;
  double paddingLeft;

  ScaleTextOption(
      {this.textOption,
      this.scaleX,
      this.scaleY,
      this.alignment,
      this.isVertical}) {
    isVertical ??= true;
    checkOption();
  }

  ScaleTextOption.vertical(this.textOption,
      {this.scaleX, this.scaleY, this.alignment}) {
    isVertical = true;
    checkOption();
  }

  ScaleTextOption.horizontal(this.textOption,
      {this.scaleX, this.scaleY, this.alignment}) {
    isVertical = false;
    checkOption();
  }

  void checkOption() {
    textOption ??= TextOption("");
    scaleX ??= 1.0;
    scaleY ??= 1.0;
    alignment ??= Alignment.center;
    TextPainter textPainter = new TextPainter();
    textPainter.textDirection = TextDirection.ltr;
    textPainter.text = new TextSpan(
        text: textOption.data,
        style: TextStyle(
          color: textOption.fontColor,
          fontSize: textOption.fontSize,
          fontStyle: textOption.fontStyle,
          fontWeight: textOption.fontWeight,
          letterSpacing: textOption.letterSpacing,
          wordSpacing: textOption.wordSpacing,
        ));
    textPainter.layout();
    if (isVertical) {
      width = textPainter.size.width * scaleX;
      paddingLeft = 0;
    } else {
      height = textPainter.size.height * scaleY;
      paddingTop = 0;
      paddingLeft = textPainter.size.width;
    }
    paddingTop = textOption.fontSize * scaleY;
  }
}

class DkScaleTextPainter extends CustomPainter {
  TextOption textOption;
  double scaleX;
  double scaleY;
  Alignment alignment;
  bool isVertical;

  ScaleTextOption scaleTextOption;

  DkScaleTextPainter(this.scaleTextOption) {
    textOption = scaleTextOption.textOption;
    scaleX = scaleTextOption.scaleX;
    scaleY = scaleTextOption.scaleY;
    alignment = scaleTextOption.alignment;
    isVertical = scaleTextOption.isVertical;
    checkOption();
  }

  void checkOption() {
    textOption ??= TextOption("");
    scaleX ??= 1.0;
    scaleY ??= 1.0;
    alignment ??= Alignment.center;
    isVertical ??= true;
  }

  @override
  void paint(Canvas canvas, Size size) {
    TextPainter textPainter = new TextPainter();
    textPainter.textDirection = TextDirection.ltr;
    textPainter.text = new TextSpan(
        text: textOption.data,
        style: TextStyle(
          color: textOption.fontColor,
          fontSize: textOption.fontSize,
          fontStyle: textOption.fontStyle,
          fontWeight: textOption.fontWeight,
          letterSpacing: textOption.letterSpacing,
          wordSpacing: textOption.wordSpacing,
        ));
    textPainter.layout();
    canvas.scale(scaleX, scaleY);
    double textStarPositionX = 0;
    double textStarPositionY = -textPainter.size.height;
    if (isVertical) {
      if (alignment.x == -1.0) {
        textStarPositionX = 0;
      } else if (alignment.x == 1.0) {
        textStarPositionX = -textPainter.size.width;
      } else if (alignment.x == 0.0) {
        textStarPositionX = -textPainter.size.width / 2;
      }
    } else {
      textStarPositionX = -textPainter.size.width;
    }
    textPainter.paint(canvas, Offset(textStarPositionX, textStarPositionY));
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
